#include "MyImage.h"
#include <math.h>


MyImage::MyImage()
{
	mColourPlane = NULL;
}

MyImage::MyImage(int nW, int nH, int nBPP, WORD Channels)
{
	Create(nW,nH,nBPP, Channels);
}
MyImage::MyImage(MyImage& Im)
{
	
	Create(Im.width,Im.height,Im.depth,Im.nChannels);
	for (int i = 0; i < 3; i++)
	{
		*(GetPlane(i)) = Im.GetPlane(i);
	}
	UpdateFromPlanes();

}

MyImage::MyImage(IplImage* Im)
{
	nSize = Im->nSize;
	ID = Im->ID;
	nChannels = Im->nChannels;
	alphaChannel = Im->alphaChannel;
	depth = Im->depth;
	width = Im->width;
	//colorModel = Im->colorModel;
	//channelSeq = Im->channelSeq;
	dataOrder = Im->dataOrder;
	origin = Im->origin;
	align = Im->align;

	height = Im->height;
	imageSize = Im->imageSize;
	imageData = Im->imageData;
	widthStep = Im->widthStep;
	mColourPlane = NULL;

}





double MyImage::f (double t)
{
	double res = 0;
	if (t > 0.008856)
		res = pow(t, 1/(double)3);
	else res = 7.787*t + 16/ (double) 116;
	return res;
}

double MyImage::f_inv (double t)
{	
	double res = 0;
	if (pow(t,3) > 0.008856)
		res = pow(t,3);
	else res = ((t - 16 /(double) 116))/7.787;
	return res;

}

void MyImage::MakePlanes()
{
	
	int Heig = height;
	int Widt = width;

	int BP = depth*3;
	void * Pixel;
	UINT8 mask = 4;
	UINT32 shift = 0;
	UINT8 cur = 0;
	UINT8 temp8 = 0;
	double temp;
	UINT32 max = 0;
	
	mColourPlane = new ColorPlane[nChannels];

	for (int i = 0; i < nChannels; i++)
	{
		(mColourPlane + i)->create(Heig,Widt,BP);
	}


	for (int i = 0; i < Heig; i++)	
	{
		Pixel = (uchar*)(imageData+i*widthStep);
		for (int j = 0; j < Widt; j++)
		{

			
			switch (BP)
			{
			case 8:
				shift = 2;
				max = 3;	
				mask = 4;
				temp8 = ((UINT8*)Pixel)[j];
				for (int k = 0; k < nChannels; k++)
				{
					cur =(temp8 & mask);
					mask *= 2;
					cur += temp8 & mask;
					cur >>= 2*(k+1);
					((mColourPlane +2- k))->SetPixel(i,j,cur/(double)max);
					mask *= 2;
				}
				break;
			case 16:
				shift = 4;
				max = 15;
				for (int k = 0; k < 3; k++)
				{
					temp = (((UINT16*)Pixel)[3*j + 2 - k])/(double)max;
					((mColourPlane + k))->SetPixel(i,j,temp);
				}
				break;
			case 24:	
				shift = 8;
				max = pow(2.0, (double)shift);
				for (int k = 0; k < nChannels; k++)
				{
					temp = (((UINT8*)Pixel)[widthStep + nChannels*j + 2 - k])/(double)max;
					((mColourPlane + k))->SetPixel(i,j,temp);
				}
				break;

			case 32:
				shift = 8;					
				max = pow(2.0, (double)shift);			
				for (int k = 0; k < nChannels; k++)
				{
					temp = (((UINT8*)Pixel)[nChannels*j + 2 - k])/(double)max;
					((mColourPlane + k))->SetPixel(i,j,temp);
				}
				break;
			}
		
		}
	}
}



void MyImage::UpdatePlanes()
{

	if (mColourPlane)
	delete[] mColourPlane;

	MakePlanes();
}
void MyImage::UpdateFromPlanes()
{
	int Heig =height;
	int Widt = width;
	
	int BP = depth*3;
	void * Pixel;
	UINT32 mask = 1;
	UINT res = 0;
	UINT32 shift = 0;
	double temp;
	UINT32 max = 0;
	UINT8 temp8 = 0, cur =0;

	for (int i = 0; i < Heig; i++)	
	{
		Pixel =(uchar*)(imageData+i*widthStep);
		for (int j = 0; j < Widt; j++)
		{


			switch (BP)
			{
			case 8:
				shift = 2;
				max = 3;
				temp8 = 0;
				for (int k = 0; k < 3; k++)
				{
				cur = floor(((mColourPlane + k))->GetPixel(i,j)*max/1);
				if (cur > 3)
				{
					cur = 3;
				} else
					if (cur < 0)
					{
						cur = 0;
					}
				cur <<= 2*(k+1);
				temp8 += cur;
				
				}
				((UINT8*)Pixel)[j] = temp8;
				break;
			case 16:
				shift = 4;
				max = pow(2.0, (double)shift);
				for (int k = 0; k < 3; k++)
				{
					((UINT16*)Pixel)[3*j + k] = ((mColourPlane + k))->GetPixel(i,j)*max/1;
				}
				break;
			case 24:	
				shift = 8;
				max = pow(2.0, (double)shift);
				for (int k = 0; k < nChannels; k++)
				{
					temp = ((((mColourPlane + k))->GetPixel(i,j))*max/1);
					if (temp > 255)
					{
						temp = 255;
					}
					((unsigned char*)Pixel)[nChannels*j + 2 - k] = floor(temp);
				}
				break;

			case 32:
				shift = 8;					
				max = pow(2.0, (double)shift);			
				for (int k = 0; k < 3; k++)
				{
					temp = (((mColourPlane + k))->GetPixel(i,j))*max/1;
					if (temp > 255)
					{
						temp = 255;
					}
					((unsigned char*)Pixel)[4*j + 2-k] = temp;
				}
				break;
			}

		}
	}
}

void MyImage::Create(int nW, int nH, int nBPP,WORD Channels )
{
	cvCreateImage( cvSize(nW, nH), nBPP,Channels  );
	mColourPlane = new ColorPlane[nChannels];
	for (int i = 0; i < nChannels; i++)
	{
		(mColourPlane + i)->create(nH,nW,nBPP);

	}
	format = RGB_;

}

//void MyImage::Load(LPCTSTR pszFileName)
//{
//	CImage::Load(pszFileName);
//
//	MakePlanes();
//
//		format = RGB_;
//}
MyImage& MyImage::operator = (MyImage* Im)
{
	int W = width;
	int H = height;

	for (int i = 0; i < H; i ++)
	{
		for (int j = 0; j < W; j++)
		{
			*(((uchar*)(imageData + widthStep*j))+i) = *(((uchar*)(Im->imageData + Im->widthStep*j))+i);
		}
	}
	if (mColourPlane  == NULL)
	MakePlanes();
	else UpdatePlanes();
	return *this;

	
}
ColorPlane* MyImage::GetPlane(int i)
{
	return (mColourPlane + i);

}
void MyImage::ConvertCMY()
{
	double max = 0;
	double temp = 0;
	if (widthStep == 32)
		max = pow((double)2, widthStep/4);	
	else max = pow((double)2, widthStep/3);

	int Heig = height;
	int Widt = width;
	for (int i = 0; i < nChannels; i++)
	{
		for (int j = 0; j < Heig; j++)
		{
			for (int k = 0; k < Widt; k++)
			{

				temp = 1 - (mColourPlane + i)->GetPixel(j,k);
				(mColourPlane + i)->SetPixel(j,k,temp);  
			}
		}
	}
		format = CMY_;

}
void MyImage::ConvertXYZ()
{
	int Heig = height;
	int Widt = width;
	double X = 0;
	double Y = 0;
	double Z = 0;
	double R,G,B;


		for (int j = 0; j < Heig; j++)
		{
			for (int k = 0; k < Widt; k++)
			{
				R = (((mColourPlane))->GetPixel(j,k));
				G = (((mColourPlane + 1))->GetPixel(j,k));
				B = (((mColourPlane + 2))->GetPixel(j,k));
				X = 0.431 * R + 0.342 * G + 0.178 * B;
				Y = 0.222 * R + 0.707 * G + 0.071 * B;
				Z = 0.020 * R + 0.130 * G + 0.939 * B;
				((mColourPlane))->SetPixel(j,k,X); 
				((mColourPlane + 1))->SetPixel(j,k,Y); 
				((mColourPlane + 2))->SetPixel(j,k,Z); 
			}
		}
		
	format = XYZ_;


}
void MyImage::ConvertHSV()
{
	int Heig = height;
	int Widt = width;
	double H = 0;
	double S = 0;
	double V = 0;
	double R,G,B;
	double maxVal = 0;
	double minVal = 0;
	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			R = (((mColourPlane))->GetPixel(j,k));
			G = (((mColourPlane + 1))->GetPixel(j,k));
			B = (((mColourPlane + 2))->GetPixel(j,k));	


			maxVal = max(R,max(G,B));
			minVal = min(R,min(G,B));
			V = maxVal;
			if (maxVal == 0)
			{
				S = 0;
			}
			else S = ((maxVal - minVal)/maxVal);
			if (S == 0) H = 0;
			else 
			{
				if (R == maxVal)				
					H = (G - B)/(maxVal - minVal);
				else if (G == maxVal)				
					H = 2 + (B - R)/(maxVal - minVal);
				else if (B == maxVal)
					H = 4 + (R - G)/(maxVal - minVal);

				H *= 60;
				if (H < 0)
					H += 360;


			}
			((mColourPlane))->SetPixel(j,k,H); 
			((mColourPlane + 1))->SetPixel(j,k,S); 
			((mColourPlane + 2))->SetPixel(j,k,V); 
		}
	}
	format = HSV_;


}
void MyImage::ConvertYUV()
{
	int Heig = height;
	int Widt = width;
	double Y = 0;
	double U = 0;
	double V = 0;
	double R,G,B;


	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			R = (((mColourPlane))->GetPixel(j,k));
			G = (((mColourPlane + 1))->GetPixel(j,k));
			B = (((mColourPlane + 2))->GetPixel(j,k));

			Y = 0.299 * R + 0.587 * G + 0.114 * B;
			U = -0.147 * R - 0.289 * G + 0.436 * B;
			V = 0.615 * R - 0.515 * G + 0.1 * B;

			((mColourPlane))->SetPixel(j,k,Y); 
			((mColourPlane + 1))->SetPixel(j,k,U); 
			((mColourPlane + 2))->SetPixel(j,k,V); 
		}
	}


	format = YUV_;

}
void MyImage::ConvertLab()
{
	int Heig = height;
	int Widt = width;
	double temp =0;
	double L = 0;
	double a = 0;
	double b = 0;
	double X,Y,Z;

	ConvertXYZ();

	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			X = (((mColourPlane))->GetPixel(j,k));
			Y = (((mColourPlane + 1))->GetPixel(j,k));
			Z = (((mColourPlane + 2))->GetPixel(j,k));
			L = 116 * f(Y) -16;
			a = 500 * (f(X) - f(Y));
			b = 200 * (f(Y) - f(Z));


			((mColourPlane))->SetPixel(j,k,L); 
			((mColourPlane + 1))->SetPixel(j,k,a); 
			((mColourPlane + 2))->SetPixel(j,k,b); 
		}
	}



	format = Lab_;
}
void MyImage::ConvertCMY_RGB()
{
	int Heig = height;
	int Widt = width;
	double temp;
	double max;
	if (widthStep == 32)
		max = pow((double)2, widthStep/4);	
	else max = pow((double)2, widthStep/3);

	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < Heig; j++)
		{
			for (int k = 0; k < Widt; k++)
			{
				temp = 1 - (((mColourPlane + i))->GetPixel(j,k));

				((mColourPlane + i))->SetPixel(j,k,temp);  

			}
		}
	}
	format = RGB_;
}
void MyImage::ConvertXYZ_RGB()
{
	int Heig = height;
	int Widt = width;
	double X = 0;
	double Y = 0;
	double Z = 0;
	double R,G,B;


	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			X = (((mColourPlane))->GetPixel(j,k));
			Y = (((mColourPlane + 1))->GetPixel(j,k));
			Z = (((mColourPlane + 2))->GetPixel(j,k));

			R = 3.063 * X - 1.393 * Y - 0.476 * Z;
			G = - 0.969 * X + 1.876 * Y + 0.042 * Z;
			B = 0.068 * X - 0.229 * Y + 1.069 * Z;

			((mColourPlane))->SetPixel(j,k,R);	

			((mColourPlane + 1))->SetPixel(j,k,G); 

			((mColourPlane + 2))->SetPixel(j,k,B); 
		}
	}

	format = RGB_;

}
void MyImage::ConvertHSV_RGB()
{
	int Heig = height;
	int Widt = width;
	double H = 0;
	double S = 0;
	double V = 0;
	double R = 0,G = 0,B = 0;
	double T = 0,P = 0,Q = 0;


	int sector = 0;
	double frac = 0;

	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			H = (((mColourPlane))->GetPixel(j,k));
			S = (((mColourPlane + 1))->GetPixel(j,k));
			V = (((mColourPlane + 2))->GetPixel(j,k));

			if (S == 0) R = G = B = V;
			else 
			{
				sector = floor(H/60);
				frac = H/60 - sector;

				T = (V * (1 - S));
				P = (V * (1 - S* frac));
				Q = (V * (1 - S*(1 - frac)));
			}				
			switch (sector)
			{
				case 0: R = V; G = Q; B = T; break;
				case 1: R = P; G = V; B = T; break;
				case 2: R = T; G = V; B = Q; break;
				case 3: R = T; G = P; B = V; break;
				case 4: R = Q; G = T; B = V; break;
				case 5: R = V; G = T; B = P; break;
			}	

			((mColourPlane))->SetPixel(j,k,R);	
			((mColourPlane + 1))->SetPixel(j,k,G); 
			((mColourPlane + 2))->SetPixel(j,k,B); 
		}
	}

		format = RGB_;
}
void MyImage::ConvertYUV_RGB()
{
	int Heig = height;
	int Widt = width;
	double Y = 0;
	double U = 0;
	double V = 0;
	double R,G,B;


	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			Y = (((mColourPlane))->GetPixel(j,k));
			U = (((mColourPlane + 1))->GetPixel(j,k));
			V = (((mColourPlane + 2))->GetPixel(j,k));

			R =  Y + 0.13983 * V;
			G =  Y - 0.39465 * U - 0.58060 * V;
			B =  Y + 2.03211 * U;

			((mColourPlane))->SetPixel(j,k,R);	

			((mColourPlane + 1))->SetPixel(j,k,G); 

			((mColourPlane + 2))->SetPixel(j,k,B); 
		}
	}
	format = RGB_;

}
void MyImage::ConvertLab_RGB()
{
	int Heig = height;
	int Widt = width;
	double temp =0;
	double L = 0;
	double a = 0;
	double b = 0;
	double X,Y,Z;


	for (int j = 0; j < Heig; j++)
	{
		for (int k = 0; k < Widt; k++)
		{
			L = (((mColourPlane))->GetPixel(j,k));
			a = (((mColourPlane + 1))->GetPixel(j,k));
			b = (((mColourPlane + 2))->GetPixel(j,k));
			Y = f_inv((L+16)/(double)116);
			X = f_inv(a / 500 + f(Y));
			Z = f_inv(f(Y) - b/200) ;

			
			((mColourPlane))->SetPixel(j,k,X); 
			((mColourPlane + 1))->SetPixel(j,k,Y); 
			((mColourPlane + 2))->SetPixel(j,k,Z); 
		}
	}

	ConvertXYZ_RGB();

	format = RGB_;

}
//
//
//
//

//void MyImage::Neg()
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlaneNeg((mColourPlane + i));	
//		
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Ln()
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlaneLn((mColourPlane + i));	
//
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Brigth_p()
//{
//
//	for (int i = 0; i < 3; i++)
//	CImageGradation::PlaneBright_p(((mColourPlane + i)));
//}
//
//void MyImage::Brigth_m()
//{	
//	for (int i = 0; i < 3; i++)
//	CImageGradation::PlaneBright_m(((mColourPlane + i)));	
//}
//void MyImage::Contrast()
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlaneContrast(((mColourPlane + i)));
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Equalize()
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlaneEqualize(((mColourPlane + i)));
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Pow(double power)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlanePow(((mColourPlane + i)),power);
//	}
//	UpdateFromPlanes();
//}
//
//void MyImage::Reduction(MyImage& Im)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		CImageGradation::PlaneReduction(((mColourPlane + i)),Im.GetPlane(i));
//	}
//	UpdateFromPlanes();
//}
//double MyImage::AverageBright()
//{
//
//	ConvertHSV();
//	double av = ((mColourPlane + 2))->AvaerageBr();
//	ConvertHSV_RGB();
//	return av;
//	
//}
//
//void MyImage::Convolution(CMask * mask)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution(mask);
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Convolution_min(int size)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution_min(size);
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Convolution_max(int size)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution_max(size);
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Convolution_med_cross(int size)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution_med_cross(size);
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Convolution_med_square(int size)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution_med_square(size);
//	}
//	UpdateFromPlanes();
//}
//void MyImage::Convolution_med_round(int size)
//{
//	for (int i = 0; i < 3; i++)
//	{
//		(mColourPlane + i)->Convolution_med_round(size);
//	}
//	UpdateFromPlanes();
//}
MyImage::~MyImage()
{

	delete [] mColourPlane;
	IplImage::~IplImage();
}
